﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;
using IExternalDataTypes;
using System.Windows.Forms;
using LoaderLib;

namespace ExcelLoader
{
    public class ExcelLoader : ILoader, IDisposable
    {
        private enum StudentEnum
        {
            Number = 1, Name = 2, UC = 5, Regime = 4, Class = 6
        }
        private enum CUnitEnum
        {
            Acronym = 1, Name = 2, Semester = 3, Course = 4
        }
        private enum CourseEnum
        {
            Acronym = 1, Name = 2
        }
        private enum ClassEnum
        {
            Name = 1
        }
        private enum TeacherEnum
        {
            ID = 1 , Name = 2
        }
        private enum RoomEnum
        {
            Description = 1,
            Seat = 2
        }
        private enum SemesterEnum
        {
            Description = 1,
            Number = 2
        }
        private enum RegimeEnum
        {
            Description = 1
        }
        private string _path = @"C:\";
        private OpenFileDialog _opf;
        private readonly Form _f;
        private Microsoft.Office.Interop.Excel.Application _xlApp;
        private Workbook _xlWorkBook;
        private Worksheet _xlWorkSheet;
        private Range _range;

        #region Implementation of ILoader<out string>

        public ExcelLoader()
        {
            _f = new Form();
            return;
        }

        public string Getname()
        {
            return "Excel Loader";
        }

        public void DataSource()
        {
            _opf = new OpenFileDialog { Filter = @"Excel Files|*.xls;*.xlsx" };
            if(_opf.ShowDialog(_f) == DialogResult.Cancel) throw new InvalidOperationException("nao foi definido um path para carregar os dados") ;
            _path = _opf.FileName;
        }

        private void OpenBook(string currentSheet)
        {
            if (_path == null) return;
            _xlApp = new Microsoft.Office.Interop.Excel.Application();
            _xlWorkBook = _xlApp.Workbooks.Open(_path, 0, true, 5, "", "", true, XlPlatform.xlWindows, "\t", false,
                                              false, 0, true, 1, 0);
            //_xlWorkSheet = (Worksheet)_xlWorkBook.Worksheets.get_Item(currentSheet);
            _xlWorkSheet = (Worksheet)_xlWorkBook.Worksheets.Item[currentSheet];
            _range = _xlWorkSheet.UsedRange;
        }

        private void CloseBook()
        {
            _xlWorkBook.Close(false, _opf.FileName, false);
            _xlApp.Quit();
        }

        public IEnumerable<IStudent> GetStudents()
        {
            OpenBook("Inscrições");
            var ls = new List<Student>();
            try
            {
                var rCnt = 2; //as cell começam em 1 e a primeira é o nome.
                do
                {
                    string name = (_range.Cells[rCnt, (int)StudentEnum.Name]).Value2;
                    string regime = (_range.Cells[rCnt, (int)StudentEnum.Regime]).Value2;
                    var number = (int)(_range.Cells[rCnt, (int)StudentEnum.Number]).Value2;
                    var lUc = new List<string>();
                    var lClass = new List<string>();
                    do
                    {
                        string sclass = (_range.Cells[rCnt, (int)StudentEnum.Class]).Value2;
                        if (!lClass.Contains(sclass))
                        {
                            lClass.Add(sclass);
                        }
                        lUc.Add((_range.Cells[rCnt, (int)StudentEnum.UC]).Value2);
                        rCnt++;
                        if (rCnt > _range.Rows.Count)
                        {
                            ls.Add(new Student { Name = name, Number = number, Subscriptions = lUc, Regime = regime, Class = lClass });
                            return ls;
                        }
                    } while (number == ((int)(_range.Cells[rCnt, (int)StudentEnum.Number]).Value2));
                    ls.Add(new Student { Name = name, Number = number, Subscriptions = lUc, Regime = regime, Class = lClass });
                } while (true);
            }
            finally
            {
                CloseBook();
            }
        }

        public IEnumerable<ICUnit> GetCUnit()
        {
            OpenBook("UC");
            var luc = new List<CUint>();
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    var stillNumber = (_range.Cells[rCnt, (int)CUnitEnum.Semester]).Value2;
                    var stringA = stillNumber.ToString().Split(',');
                    var rawCourse = (_range.Cells[rCnt, (int)CUnitEnum.Course]).Value2;
                    var stringACourse = rawCourse.ToString().Split(',');
                    luc.Add(new CUint
                                {
                                    Acronym = (_range.Cells[rCnt, (int)CUnitEnum.Acronym]).Value2,
                                    Name = (_range.Cells[rCnt, (int)CUnitEnum.Name]).Value2,
                                    Semesters = stringA,
                                    Course = stringACourse
                                });
                }
            }
            finally
            {
                CloseBook();
            }
            return luc;
        }

        public IEnumerable<ICourse> GetCourse()
        {
            OpenBook("Curso");
            var lc = new List<ICourse>();
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    lc.Add(new Course
                    {
                        Acronym = (_range.Cells[rCnt, (int)CourseEnum.Acronym]).Value2,
                        Name = (_range.Cells[rCnt, (int)CourseEnum.Name]).Value2,
                    });
                }
            }
            finally
            {
                CloseBook();
            }
            return lc;
        }

        public IEnumerable<IClass> GetClass()
        {
            OpenBook("Turmas");
            var lc = new List<IClass>();
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    var rawString = (_range.Cells[rCnt, (int)ClassEnum.Name]).Value2;
                    var charArray = rawString.ToString().ToCharArray();
                    string course = charArray[0].ToString() + charArray[1].ToString();
                    switch (course)
                    {
                        case "LI":
                            course = "LEIC";
                            break;
                        case "LT":
                            course = "LEETC";
                            break;
                        case "LM":
                            course = "LERCM";
                            break;
                    }
                    lc.Add(new Class()
                               {
                                   Name = rawString,
                                   Courses = course,
                                   Regime = charArray[4].ToString(),
                                   Semester = charArray[2].ToString(),
                                   subClass = charArray[3].ToString(),
                               });
                }
            }
            finally
            {
                CloseBook();
            }
            return lc;
        }

        public IEnumerable<ITeacher> GetTeacher()
        {
            OpenBook("Professores");
            var lt = new List<ITeacher>();
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    lt.Add(new Teacher()
                               {
                                   Name = (_range.Cells[rCnt, (int)TeacherEnum.Name]).Value2,
                                   ID = (int)((_range.Cells[rCnt, (int)TeacherEnum.ID]).Value2)
                               });
                }
            }
            finally
            {
                CloseBook();
            }
            return lt;
        }

        public IEnumerable<IRoom> GetRoom()
        {
            OpenBook("Sala");
            var lr = new List<IRoom>();
            
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    lr.Add(new Room()
                    {
                        Description = (_range.Cells[rCnt, (int)RoomEnum.Description]).Value2,
                        ID = rCnt - 1,
                        Seats = (int)(_range.Cells[rCnt, (int)RoomEnum.Seat]).Value2
                    });
                }
            }
            finally
            {
                CloseBook();
            }
            return lr;
        }

        public IEnumerable<ISemester> GetSemester()
        {
            OpenBook("Semestre");
            var lr = new List<ISemester>();
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    lr.Add(new Semester
                    {
                        Description = ((_range.Cells[rCnt, (int)SemesterEnum.Description]).Value2).ToString(),
                        Number = int.Parse(((_range.Cells[rCnt, (int)SemesterEnum.Number]).Value2).ToString())//rCnt - 1
                    });
                }
            }
            finally
            {
                CloseBook();
            }
            return lr;
        }

        public IEnumerable<IRegime> GetRegime()
        {
            OpenBook("Regime");
            var lr = new List<IRegime>();
            try
            {
                for (var rCnt = 2; rCnt <= _range.Rows.Count; rCnt++)
                {
                    lr.Add(new Regime()
                    {
                        Description = (_range.Cells[rCnt, (int)RegimeEnum.Description]).Value2,
                        ID = rCnt - 1
                    });
                }
            }
            finally
            {
                CloseBook();
            }
            return lr;
        }

        #endregion

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        protected virtual void Dispose(bool disposing)
        {
            try
            {
                while (Marshal.ReleaseComObject(_range) != 0) ;
                while (Marshal.ReleaseComObject(_xlWorkSheet) != 0) ;
                while (Marshal.ReleaseComObject(_xlWorkBook.Worksheets) != 0) ;
                while (Marshal.ReleaseComObject(_xlWorkBook) != 0) ;
                while (Marshal.ReleaseComObject(_xlApp) != 0) ;
                _range = null;
                _xlWorkSheet = null;
                _xlWorkBook = null;
                _xlApp = null;
            }
            catch (Exception ex)
            {
                _range = null;
                _xlWorkSheet = null;
                _xlWorkBook = null;
                _xlApp = null;
                MessageBox.Show("Unable to release the Object " + ex);
            }
            finally
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }
    }
}


internal class Student : IStudent
{
    public int Number { get; set; }
    public string Name { get; set; }
    public string Regime { get; set; }
    public IEnumerable<string> Class { get; set; }
    public IEnumerable<string> Subscriptions { get; set; }
}

internal class Semester : ISemester
{
    public int Number { get; set; }
    public string Description { get; set; }
}

internal class CUint : ICUnit
{
    public string Acronym { get; set; }
    public string Name { get; set; }
    public IEnumerable<string> Semesters { get; set; }
    public IEnumerable<string> Teacher { get; set; }
    public IEnumerable<string> Course { get; set; }
}

internal class Course : ICourse
{
    public string Acronym { get; set; }
    public string Name { get; set; }
}

internal class Regime : IRegime
{
    public int ID { get; set; }
    public string Description { get; set; }
}

internal class Class : IClass
{
    public string Name { get; set; }
    public string Regime { get; set; }
    public string Courses { get; set; }
    public string Semester { get; set; }
    public string subClass { get; set; }
}

internal class Teacher : ITeacher
{
    public int ID { get; set; }
    public string Name { get; set; }
}

internal class Room : IRoom
{
    public int ID { get; set; }
    public string Description { get; set; }
    public int Seats { get; set; }
}
